继承和模块

1. 继承

1.1 什么是继承?

继承是面向对象编程中的一个重要概念,它允许一个类(子类)继承另一个类(父类)的属性和方法。通过继承,子类可以重用父类的代码,并且可以添加新的属性和方法,或者覆盖父类的方法。

1.2 继承的语法

在 Ruby 中,使用 class 关键字定义一个类,并使用 < 符号表示继承关系。例如:

class Animal
  def speak
    puts "Some generic animal sound"
  end
end

class Dog < Animal
  def speak
    puts "Woof!"
  end
end

dog = Dog.new
dog.speak  # 输出: Woof!

在这个例子中,Dog 类继承了 Animal 类。Dog 类中的 speak 方法覆盖了 Animal 类中的 speak 方法。

1.3 继承中的方法覆盖

子类可以覆盖父类的方法,也可以通过 super 关键字调用父类的方法。例如:

class Animal
  def speak
    puts "Some generic animal sound"
  end
end

class Cat < Animal
  def speak
    super
    puts "Meow!"
  end
end

cat = Cat.new
cat.speak  # 输出: Some generic animal sound
           # 输出: Meow!

在这个例子中,Cat 类中的 speak 方法首先调用了父类 Animal 的 speak 方法,然后输出 "Meow!"。

2. 模块

2.1 什么是模块?

模块是 Ruby 中的一种组织代码的方式,它类似于类,但不能被实例化。模块主要用于封装一组相关的常量、方法和类。模块可以被其他类或模块包含(mixin),从而实现代码的复用。

2.2 模块的定义和使用

使用 module 关键字定义一个模块。例如:

module Greeting
  def hello
    puts "Hello!"
  end
end

class Person
  include Greeting
end

person = Person.new
person.hello  # 输出: Hello!

在这个例子中,Greeting 模块定义了一个 hello 方法。Person 类通过 include 关键字将 Greeting 模块包含进来,从而可以使用 hello 方法。

2.3 模块的命名空间

模块还可以用作命名空间,避免类名冲突。例如:

module Math
  class Calculator
    def add(a, b)
      a + b
    end
  end
end

calculator = Math::Calculator.new
puts calculator.add(2, 3)  # 输出: 5

在这个例子中,Math 模块作为命名空间,Calculator 类被定义在 Math 模块中,避免了与其他 Calculator 类的冲突。

3. 混入 (Mixin) 技术

3.1 什么是混入?

混入(Mixin)是一种将模块的功能添加到类中的技术。通过 include 或 prepend 关键字,模块的方法可以被类直接使用,就像类的实例方法一样。

3.2 使用 include 和 prepend

include 将模块的方法作为类的实例方法,而 prepend 将模块的方法插入到类的继承链的前面。例如:

module Logging
  def log(message)
    puts "[LOG] #{message}"
  end
end

class User
  include Logging

  def initialize(name)
    @name = name
    log("User #{@name} created")
  end
end

user = User.new("Alice")  # 输出: [LOG] User Alice created

在这个例子中,Logging 模块的 log 方法被 User 类包含,并在 initialize 方法中使用。

3.3 混入的顺序

include 和 prepend 的顺序会影响方法的查找顺序。include 的方法会在类的继承链的后面,而 prepend 的方法会在继承链的前面。例如:

module A
  def foo
    puts "A's foo"
  end
end

module B
  def foo
    puts "B's foo"
  end
end

class C
  include A
  include B

  def foo
    puts "C's foo"
  end
end

c = C.new
c.foo  # 输出: B's foo

在这个例子中,B 模块的 foo 方法覆盖了 A 模块的 foo 方法,因为 B 模块在 A 模块之后被包含。

4. 实践练习

4.1 练习:创建一个继承链

创建一个 Vehicle 类,然后创建 Car 和 Truck 类继承 Vehicle 类。每个类都有自己的 start 方法,并且 Truck 类覆盖 Vehicle 类的 start 方法。

class Vehicle
  def start
    puts "Vehicle started"
  end
end

class Car < Vehicle
  def start
    puts "Car started"
  end
end

class Truck < Vehicle
  def start
    super
    puts "Truck started"
  end
end

car = Car.new
car.start  # 输出: Car started

truck = Truck.new
truck.start  # 输出: Vehicle started
             # 输出: Truck started

4.2 练习:使用模块实现混入

创建一个 Logger 模块,包含一个 log 方法。然后创建一个 Employee 类,包含 Logger 模块,并在 initialize 方法中使用 log 方法记录员工信息。

module Logger
  def log(message)
    puts "[LOG] #{message}"
  end
end

class Employee
  include Logger

  def initialize(name, position)
    @name = name
    @position = position
    log("Employee #{@name} (#{@position}) created")
  end
end

employee = Employee.new("Bob", "Manager")  # 输出: [LOG] Employee Bob (Manager) created

5. 总结

继承和模块是 Ruby 中实现代码复用和组织的重要工具。继承允许子类继承父类的属性和方法,而模块则通过混入技术将方法添加到类中。通过合理使用继承和模块,可以提高代码的可维护性和可扩展性。

希望这篇教程能帮助你更好地理解 Ruby 中的继承和模块。继续练习和探索,你将能够更熟练地使用这些强大的工具来构建复杂的应用程序。